// VirtualChannelTesApp.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <RdcTransportLib/RdcTransport.h>

#include <memory>
#include <algorithm>
#include <iostream>
#include <conio.h>

#include <boost/thread.hpp>

#include <plog/log.h>

namespace {
    std::auto_ptr<rdc_transport::IVirtChannel>  channel;
    std::vector<char>                           tmp_read_buffer;
    bool                                        is_data_read = false;

    boost::mutex                                io_mutex;
    boost::mutex                                on_read_mutex;
    boost::shared_mutex                         read_buffer_mutex;
    boost::condition_variable_any               is_read_cond;

    //HANDLE                                      read_event = NULL;
    //HANDLE                                      EventReadON;


    struct testConnectionCallback 
        : public rdc_transport::IServerVirtChannelCallback
    {
        void OnDisconnect()
        {
            ;
        }
        void OnReconnect()
        {
            ;
        }
    };

    struct testReadHandler : public rdc_transport::IReadHandler
    {
        void OnRead(std::vector<char>* pBuffer)
        {
            boost::unique_lock<boost::mutex> lock(on_read_mutex);

            try
            {
                /*tmp_read_buffer.resize (pBuffer->size());
                std::copy (pBuffer->begin(), pBuffer->end(), tmp_read_buffer.begin());*/
                {
                    //boost::mutex::scoped_lock lock(mutex);
                    boost::lock_guard<boost::shared_mutex> lock(read_buffer_mutex);

                    tmp_read_buffer.resize (pBuffer->size());
                    std::copy (pBuffer->begin(), pBuffer->end(), tmp_read_buffer.begin());

                    is_data_read = true;
                }
                is_read_cond.notify_all();

                {
                    std::ostringstream out_ss;
                    out_ss << "Buffer(" << pBuffer->size() << "): ";
                    if (pBuffer->size() > 250)
                        out_ss << "size is " << pBuffer->size();
                    else {
                        std::ostream_iterator<char> out_string_stream_it(out_ss, "");
                        std::copy(pBuffer->begin(), pBuffer->end(), out_string_stream_it);
                    }
                                        
                    LOG(plog::info) << out_ss.str().c_str();
                }
                
                {
                    //boost::mutex::scoped_lock lock(mutex);
                    boost::unique_lock<boost::shared_mutex> lock(read_buffer_mutex);
                    while (is_data_read)
                    {
                        is_read_cond.wait(lock);
                    }
                }

                LOG(plog::info) << "OnRead";
                
                boost::mutex::scoped_lock lock(io_mutex);
                std::cout << "OnRead\n";
                
                //::SetEvent (read_event);
				//WaitForSingleObject(EventReadON);
            }
            catch(std::exception& ex)
            {
                LOG(plog::error) <<  ex.what();
            }
        }
        void OnReadFail(const char* what)
        {
            LOG(plog::error) << "Server OnReadFail: " << what;
        }
    };

    void SendToClient (std::vector<char>& buf)
    {
        LOG(plog::info) << "SendToClient";
        std::cout << "SendToClient\n";
        channel->Write(&buf);
    }
 //void packetisaccepted(bool arg)
 //{
	// if (arg)
	//	 SetEvent(EventReadON);
 //}

    void RecvFromClient (std::vector<char>& buf)
    {
        LOG(plog::info) << "RecvFromClient";
        std::cout << "RecvFromClient\n";
        //::WaitForSingleObject (read_event, INFINITE);

        {
            boost::shared_lock<boost::shared_mutex> lock(read_buffer_mutex);
            while (!is_data_read)
            {
                is_read_cond.wait(lock);
            }
            
            buf.resize( tmp_read_buffer.size() );
            std::copy (tmp_read_buffer.begin(), tmp_read_buffer.end(), buf.begin());
        }
        {
            boost::unique_lock<boost::shared_mutex> lock(read_buffer_mutex);
            is_data_read = false;
            is_read_cond.notify_one();
        }
        //::ResetEvent(read_event);

        boost::mutex::scoped_lock lock(io_mutex);

        std::cout << "Buffer(size:" << buf.size() << "): ";
        std::copy (buf.begin(), buf.end(), std::ostream_iterator<char>(std::cout,""));
        std::cout << std::endl;
    }

}

int _tmain(int argc, _TCHAR* argv[])
{
    plog::initialize_log(L"VirtualChannelTestApp.csv", plog::error);
    //read_event = ::CreateEvent (NULL, TRUE, FALSE, NULL);
	//EventReadON = ::CreateEvent (NULL, TRUE, FALSE, NULL);
    
    try
    {
        _getch();

        testReadHandler rh;
        testConnectionCallback cc;

        //std::auto_ptr<rdc_transport::IVirtChannel> ch = 
        channel = rdc_transport::CreateServerChannel("WSCKDR", L"WSCKDR",&cc, &rh);

        std::vector<char> buffer_(100,'a');
        SendToClient (buffer_);

        std::vector<char> buffer1_(100,'A');
        SendToClient (buffer1_);

        std::vector<char> buffer2_(3000,'b');
        SendToClient (buffer2_);

        std::vector<char> buffer;
        RecvFromClient (buffer);
        
        _getch();

        std::vector<char> buffer1;
        RecvFromClient (buffer1);
        _getch();

        std::vector<char> buffer2;
        RecvFromClient (buffer2);
        _getch();

        std::vector<char> buffer3_(100,'B');
        SendToClient (buffer3_);

        std::vector<char> buffer3;
        RecvFromClient (buffer3);
        _getch();
    }
    catch(std::exception& ex)
    {
        std::cout<<ex.what();
    }

    plog::release_log();
    return 0;
}
